<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <title>dex2oat原理篇 - Jin&#39;s Blog</title>
  <meta name="renderer" content="webkit" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>

<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />

<meta name="theme-color" content="#f8f5ec" />
<meta name="msapplication-navbutton-color" content="#f8f5ec">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="#f8f5ec">


<meta name="author" content="Jin" /><meta name="description" content="1、虚拟机 1.1、Android虚拟机编年史 Android虚拟机主要有两种：Davlik和Art，Art在Android L后正式成为了默认的" /><meta name="keywords" content="Hugo, theme, even" />






<meta name="generator" content="Hugo 0.78.2 with theme even" />


<link rel="canonical" href="https://acidsweet.gitee.io/post/dex2oat/" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/manifest.json">
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">



<link href="/sass/main.min.3460a402f69e3b9f68e5768c74d60eb00b438e2bff71a6dd2ac4947b8e4b09c8.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.1.20/dist/jquery.fancybox.min.css" integrity="sha256-7TyXnr2YU040zfSP+rEcz29ggW4j56/ujTPwjMzyqFY=" crossorigin="anonymous">


<meta property="og:title" content="dex2oat原理篇" />
<meta property="og:description" content="1、虚拟机 1.1、Android虚拟机编年史 Android虚拟机主要有两种：Davlik和Art，Art在Android L后正式成为了默认的" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://acidsweet.gitee.io/post/dex2oat/" />
<meta property="article:published_time" content="2021-09-22T20:23:21+08:00" />
<meta property="article:modified_time" content="2021-09-22T20:23:21+08:00" />
<meta itemprop="name" content="dex2oat原理篇">
<meta itemprop="description" content="1、虚拟机 1.1、Android虚拟机编年史 Android虚拟机主要有两种：Davlik和Art，Art在Android L后正式成为了默认的">
<meta itemprop="datePublished" content="2021-09-22T20:23:21+08:00" />
<meta itemprop="dateModified" content="2021-09-22T20:23:21+08:00" />
<meta itemprop="wordCount" content="2140">



<meta itemprop="keywords" content="" />
<meta name="twitter:card" content="summary"/>
<meta name="twitter:title" content="dex2oat原理篇"/>
<meta name="twitter:description" content="1、虚拟机 1.1、Android虚拟机编年史 Android虚拟机主要有两种：Davlik和Art，Art在Android L后正式成为了默认的"/>

<!--[if lte IE 9]>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/classlist/1.1.20170427/classList.min.js"></script>
<![endif]-->

<!--[if lt IE 9]>
  <script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
<![endif]-->

</head>
<body>
  <div id="mobile-navbar" class="mobile-navbar">
  <div class="mobile-header-logo">
    <a href="/" class="logo">Jin&#39;s Blog</a>
  </div>
  <div class="mobile-navbar-icon">
    <span></span>
    <span></span>
    <span></span>
  </div>
</div>
<nav id="mobile-menu" class="mobile-menu slideout-menu">
  <ul class="mobile-menu-list">
    <a href="/post/">
        <li class="mobile-menu-item">Archives</li>
      </a><a href="/tags/">
        <li class="mobile-menu-item">Tags</li>
      </a><a href="/categories/">
        <li class="mobile-menu-item">Categories</li>
      </a><a href="/index.xml">
        <li class="mobile-menu-item">Rss</li>
      </a>
  </ul>

  


</nav>

  <div class="container" id="mobile-panel">
    <header id="header" class="header">
        <div class="logo-wrapper">
  <a href="/" class="logo">Jin&#39;s Blog</a>
</div>





<nav class="site-navbar">
  <ul id="menu" class="menu">
    <li class="menu-item">
        <a class="menu-item-link" href="/post/">Archives</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/tags/">Tags</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/categories/">Categories</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/index.xml">Rss</a>
      </li>
  </ul>
</nav>

    </header>

    <main id="main" class="main">
      <div class="content-wrapper">
        <div id="content" class="content">
          <script type="text/javascript" async
        src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
        MathJax.Hub.Config({
        tex2jax: {
          inlineMath: [['$','$'], ['\\(','\\)']],
          displayMath: [['$$','$$']],
          processEscapes: true,
          processEnvironments: true,
          skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
          TeX: { equationNumbers: { autoNumber: "AMS" },
               extensions: ["AMSmath.js", "AMSsymbols.js"] }
        }
        });
        MathJax.Hub.Queue(function() {
          
          
          
          var all = MathJax.Hub.getAllJax(), i;
          for(i = 0; i < all.length; i += 1) {
              all[i].SourceElement().parentNode.className += ' has-jax';
          }
        });
      
        MathJax.Hub.Config({
        
        TeX: { equationNumbers: { autoNumber: "AMS" } }
        });
      </script>
      
  <article class="post">
    
    <header class="post-header">
      <h1 class="post-title">dex2oat原理篇</h1>

      <div class="post-meta">
        <span class="post-time"> 2021-09-22 </span>
        
          <span class="more-meta"> 2140 words </span>
          <span class="more-meta"> 5 mins read </span>
        
      </div>
    </header>

    <div class="post-toc" id="post-toc">
  <h2 class="post-toc-title">Contents</h2>
  <div class="post-toc-content always-active">
    <nav id="TableOfContents">
  <ul>
    <li><a href="#1虚拟机">1、虚拟机</a>
      <ul>
        <li><a href="#11android虚拟机编年史">1.1、Android虚拟机编年史</a></li>
        <li><a href="#12虚拟机和字节码">1.2、虚拟机和字节码</a></li>
      </ul>
    </li>
    <li><a href="#2dexodex以及vdex">2、dex、odex以及vdex</a>
      <ul>
        <li><a href="#21dex文件">2.1、dex文件</a></li>
        <li><a href="#22odexoptimized-dex文件">2.2、odex(optimized dex)文件</a></li>
        <li><a href="#22vdexverified-dex">2.2、vdex(verified dex)</a></li>
      </ul>
    </li>
    <li><a href="#3dex2oat">3、dex2oat</a>
      <ul>
        <li><a href="#31触发时机">3.1、触发时机</a></li>
        <li><a href="#32编译级别">3.2、编译级别</a></li>
      </ul>
    </li>
  </ul>
</nav>
  </div>
</div>
    <div class="post-content">
      <h1 id="1虚拟机">1、虚拟机</h1>
<h2 id="11android虚拟机编年史">1.1、Android虚拟机编年史</h2>
<p><img src="https://i.loli.net/2021/09/22/cB5tgGPTXbKfdrE.png" alt="img"></p>
<p>Android虚拟机主要有两种：Davlik和Art，Art在Android L后正式成为了默认的虚拟机；有点年岁的用户可能经历过可以在开发者选项切换虚拟机的时代🐶</p>
<blockquote>
<p>JIT vs AOT</p>
</blockquote>
<blockquote>
<p><code>JIT(just in time)</code>:在运行时编译，边运行边编译。每启动一个应用程序，都会相应地启动一个 dalvik 虚拟机，启动时会建立JIT 线程，一直在后台运行。当某段代码被调用时，虚拟机会判断它是否需要编译成机器码，如果需要，就做一个标记，JIT 线程不断判断此标记，如果发现被设定就把它编译成机器码，并将其机器码地址及相关信息放入 entry table 中，下次执行到此就跳到机器码段执行，而不再解释执行，从而提高速度。【运行时优化】</p>
</blockquote>
<blockquote>
<p><img src="https://i.loli.net/2021/09/22/tg1EbOqh9kupw4z.png" alt="img"></p>
</blockquote>
<blockquote>
<p><code>AOT(ahead of time)</code>:在APK安装的时候就会做预先编译动作，编译好的文件是OAT文件，该文件本质上是一个ELF文件，它是可以直接被执行的文件。【编译时优化】</p>
</blockquote>
<blockquote>
<p><img src="https://i.loli.net/2021/09/22/RtFDox2mZ9M7q3e.png" alt="img"></p>
</blockquote>
<blockquote>
</blockquote>
<blockquote>
<p><code>混合运行时</code>:Android N后Google探索了一个结合JIT和AOT的混合策略：</p>
</blockquote>
<ul>
<li>
<blockquote>
<p>应用在安装时不做编译，而是解释字节码，所以可以快速启动</p>
</blockquote>
</li>
<li>
<blockquote>
<p>JIT的数据被分析并保存(profile文件)，在设备空闲、充电时进行AOT编译</p>
</blockquote>
</li>
</ul>
<blockquote>
<p><img src="https://i.loli.net/2021/09/22/SuWGpHFCZirlqXv.png" alt="img"></p>
</blockquote>
<h2 id="12虚拟机和字节码">1.2、虚拟机和字节码</h2>
<p><img src="https://i.loli.net/2021/09/22/ujVlfqCAP5nzxFG.png" alt="img"></p>
<ul>
<li>传统的jvm：.java&ndash;[javac]&ndash;&gt;.class</li>
<li>Android虚拟机：.java&ndash;[javac]&ndash;&gt;.class&ndash;[dx]&ndash;&gt;.dex</li>
</ul>
<blockquote>
<p>Dalvik vs Art</p>
</blockquote>
<blockquote>
<p><img src="https://i.loli.net/2021/09/22/zHXCDYqudRphIy8.png" alt="img"></p>
</blockquote>
<h1 id="2dexodex以及vdex">2、dex、odex以及vdex</h1>
<h2 id="21dex文件">2.1、dex文件</h2>
<p><img src="https://i.loli.net/2021/09/22/SY65TRICg1xkEGW.png" alt="img"></p>
<p><img src="https://i.loli.net/2021/09/22/VbR286ywtoZfnu7.png" alt="img"></p>
<blockquote>
<p><a href="https://blog.csdn.net/dashuniuniu/article/details/50347149">基于栈的虚拟机 VS 基于寄存器的虚拟机</a></p>
</blockquote>
<h2 id="22odexoptimized-dex文件">2.2、odex(optimized dex)文件</h2>
<p><code>Dalvik VM</code>:apk文件的本质是zip包，字节码分布在其中的classes*.dex内，为了优化每次unzip和一些依赖的耗时，Dalvik下会通过<code>dexopt</code>将apk中的dex抽出，优化成odex文件，存在<code>/data/dalvik-cache/</code>下(并且会删除apk内dex)；这样带来三个主要好处：</p>
<ul>
<li>启动时不需要解压apk获取dex文件了 → 启动耗时优化</li>
<li>同一时刻一个应用不会存在两份dex了 → 内存占用优化</li>
<li>apk不包括dex了，提取或者反编译难度变大 → 安全优化</li>
</ul>
<p><code>Art VM</code>:在Art虚拟机下，odex文件本质是oat文件，也就是可以被linux底层直接运行的可执行文件。Art下会通过dex2oat将apk中的dex优化成odex(oat文件)。</p>
<blockquote>
<p>ELF&amp;OAT</p>
</blockquote>
<blockquote>
<p><code>ELF(Executable and Linking Format)</code>是一种对象文件的格式，用于定义不同类型的对象文件(Object files)中都放了什么东西、以及都以什么样的格式去放这些东西。它自最早在 System V系统上出现后，被 xNIX 世界所广泛接受，作为缺省的二进制文件格式来使用。可以说，ELF 是构成众多 xNIX 系统的基础之一。</p>
</blockquote>
<blockquote>
<p><code>OAT文件</code>是一种Android私有ELF文件格式，它不仅包含有从DEX文件翻译而来的本地机器指令，还包含有原来的DEX文件内容。APK在安装的过程中，会通过dex2oat工具生成一个OAT文件。对于apk来说，oat文件实际上就是对odex文件的包装，即oat=odex，而对于一些framework中的一些jar包，会生成相应的oat尾缀的文件</p>
</blockquote>
<h2 id="22vdexverified-dex">2.2、vdex(verified dex)</h2>
<p>Android O(8.0)后，为了降低dex2oat的耗时、避免不必要的验证Dex文件合法性的过程，Android引入了vdex机制。</p>
<ul>
<li>Vdex = dex + quicken info</li>
</ul>
<p>而这时候dex2oat再也不是直接从dex生成odex了，而是从vdex中抽取文件生成odex</p>
<ul>
<li>全部源码 = vdex + odex</li>
</ul>
<h1 id="3dex2oat">3、dex2oat</h1>
<p>上面两个章节我们回顾Android虚拟机的一些事情，知道了在目前主流的Art虚拟机下通过AOT技术会将vdex转换成odex文件，这样可以有效的提高应用的执行效率。而这个转化过程正是通过系统的dex2oat工具完成的，这个章节会来了解一下dex2oat相关的知识。</p>
<h2 id="31触发时机">3.1、触发时机</h2>
<p><img src="https://i.loli.net/2021/09/22/1FE4Uldjk7fMe9h.png" alt="img"></p>
<h2 id="32编译级别">3.2、编译级别</h2>
<p><img src="https://i.loli.net/2021/09/22/a4o3MrGgnKiBywT.png" alt="img"></p>
<p><img src="https://i.loli.net/2021/09/22/WQC2hwP9k84MyHb.png" alt="img"></p>
<p>我们知道vdex+odex=全部代码，当odex越大，vdex越小时，我们优化编译的效果也越好；所以上面的编译级别也会遵循占用空间越大，编译优化效果越好的原则，主要几个级别编译效果：</p>
<p><strong>verify&lt;space&lt;speed&lt;everything</strong></p>
<p>在Android N后由于混合模式的采用，多出了几个**-profile的模式；这里主要涉及到profile文件的生成，篇幅原因可以参考<a href="https://blog.csdn.net/hl09083253cy/article/details/78418809">Android profile-guided dex2oat_大将军王虎剩的专栏</a>中的profile-guide内容。</p>
<blockquote>
<p>profile文件：/data/misc/profiles/cur/0/com.***.home/primary.prof</p>
</blockquote>
<blockquote>
<p>每个app的profile文件都在 /data/misc/profiles/ 目录下。profile文件用来记录运行比较频繁的代码，用来进行 profile-guide 编译，使得 dex2oat编译代码更精准。</p>
</blockquote>
<blockquote>
<p>profile的创建</p>
</blockquote>
<blockquote>
<p>App安装的过程中，会调用到 isntalld的 create_app_data()函数，</p>
</blockquote>
<blockquote>
<p>如果当前支持profile编译，则会为app创建 profile文件。</p>
</blockquote>
<blockquote>
<p>查看系统定义的几个场景的编译级别</p>
</blockquote>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">→ adb shell getprop

...

[pm.dexopt.ab-ota]: [speed-profile]

[pm.dexopt.bg-dexopt]: [speed-profile]

[pm.dexopt.boot]: [verify]

[pm.dexopt.first-boot]: [quicken]

[pm.dexopt.inactive]: [verify]

[pm.dexopt.install]: [speed-profile]

[pm.dexopt.shared]: [speed]
</code></pre></td></tr></table>
</div>
</div><p>REF:</p>
<p>[1] <a href="https://www.jianshu.com/p/bcc4a9209ef5">Android虚拟机的JIT编译器</a></p>
<p>[2] <a href="https://www.jianshu.com/p/389911e2cdfb">Dalvik,ART与ODEX相爱相生</a></p>
<p>[3] [Android<a href="https://blog.csdn.net/TaylorPotter/article/details/89855346">art]-Android dex，odex，oat，vdex，art文件结构学习总结</a></p>

    </div>

    <div class="post-copyright">
  
  
  
  
</div>
<footer class="post-footer">
      
      <nav class="post-nav">
        
        <a class="next" href="/post/fundamental_analysis_primer/">
            <span class="next-text nav-default">基本面分析基础</span>
            <span class="next-text nav-mobile">Next</span>
            <i class="iconfont icon-right"></i>
          </a>
      </nav>
    </footer>
  </article>
        </div>
        <div id="disqus_thread"></div>
    <script type="text/javascript">
    (function() {
      
      
      if (window.location.hostname === 'localhost') return;

      var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
      var disqus_shortname = 'Jin';
      dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
      (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
    })();
    </script>
    <noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>

  

  

      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="social-links">
</div>

<div class="copyright">
  <span class="power-by">
    Powered by <a class="hexo-link" href="https://gohugo.io">Hugo</a>
  </span>
  <span class="division">|</span>
  <span class="theme-info">
    Theme - 
    <a class="theme-link" href="https://github.com/olOwOlo/hugo-theme-even">Even</a>
  </span>

  

  <span class="copyright-year">
    &copy; 
    2021<span class="heart"><i class="iconfont icon-heart"></i></span><span>author by jin.shang</span>
  </span>
</div>

    </footer>

    <div class="back-to-top" id="back-to-top">
      <i class="iconfont icon-up"></i>
    </div>
  </div>
  
  <script src="https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/slideout@1.0.1/dist/slideout.min.js" integrity="sha256-t+zJ/g8/KXIJMjSVQdnibt4dlaDxc9zXr/9oNPeWqdg=" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.1.20/dist/jquery.fancybox.min.js" integrity="sha256-XVLffZaxoWfGUEbdzuLi7pwaUJv1cecsQJQqGLe7axY=" crossorigin="anonymous"></script>



<script type="text/javascript" src="/js/main.min.c12618f9a600c40bd024996677e951e64d3487006775aeb22e200c990006c5c7.js"></script>
  <script type="text/javascript">
    window.MathJax = {
      tex: {
        inlineMath: [['$','$'], ['\\(','\\)']],
        tags: 'ams',
        }
    };
  </script>
  <script type="text/javascript" async src="/lib/mathjax/es5/tex-mml-chtml.js"></script>








</body>
</html>
